/**
 * @file store.c
 * @author Linquan  
 * @brief 
 * @version 0.1
 * @date 2024-02-26
 * 
 * @copyright Copyright (c) 2024
 * change history:
 *  2024-3-2 增加在内部索引为0时，擦除当前页，重新开始存
 *  2024-3-5 增加 读取模块，可以读取某几种类型，记录种类按照命令下发的顺序排着发送。
 *  2024-3-13 修改三个bug
 *  2024-3-18 优化注释，读取发送缓冲区独立为全局数组。
 */

#include "store.h"
#include "stdio.h"
#include "stdint.h"
#include "nvm.h"
#include "c_mem.h"


#define DISABLE_IRQ()   //__disable_irq()
#define ENABLE_IRQ()    //__enable_irq()



static void index_change(ENU_MESSAGE_TYPE message );

/***************** 存储 ****************************/
// 索引结构体
typedef struct record_index
{
    uint16_t in_record_num;     /* 内部存储的条数    ,数值是指向下一个存储位置 */ 
    uint16_t out_blocks_num;    /* 外部存储到第几块，value from 0 */ 
    uint16_t out_page_num;      /* 外部存储到第几页 */ 
    uint8_t  out_is_cycle;      /* 外部存储是否开始循环 */    
    uint8_t  Crc;           
}STR_RECORD_INDEX;


// 关联 数据存储类型和存储地址的索引  relate between type and store address
typedef struct 
{    
    uint8_t  out_addr_index;   /* 该数据类型的 外部存储 索引 */      
    uint8_t  in_addr_index;    /* 该数据类型的 内部存储 索引 */       
}STR_ADDR_INDEX;



/************** 读取 ************************/
#define SET_SEND(status_seq)       (status_seq = (status_seq | 0xA0))       /* 设置发送状态 */ 
#define RESET_SEND(status_seq)      (status_seq = (status_seq & 0x0F))      /* 关闭发送状态 */ 
#define IS_IN_SEND(status_seq)      ((status_seq & 0XA0) == 0XA0 ? 1:0)     /* 判断是否处于发送状态 */ 
#define GET_SEQ(status_seq)         (status_seq & 0X0F)                     /* 获得当前发送顺序 */ 

// 每种类型读取的顺序枚举
typedef enum
{  
    ENU_OUT_BLOCK_PAGES_READ , 
    ENU_IN_BUFF_READ,
    ENU_READ_FINFISH,
       
}ENU_TYPE_READ_SEQUENCE;


// 读取索引结构
typedef struct 
{
    uint8_t                start_read_flag; /* 是否允许读取标志 */ 
    uint8_t                read_status_seq; /* 读取状态 */ 
    uint16_t               blocks_num;      /* 当前读取的块位置 */ 
    uint16_t               pages;           /* 当前读取的外部flash页位置 */ 
    uint16_t               in_record_num;   /* 当前读取的内部flash条数 */ 

    uint16_t     send_num;                  /*  需要发送的条数    */ 
}STR_READ_INDEX;


/////////// 读取管理 /////////////////
#define     MESSAGE_TYPR_BUF_NUM 8
typedef struct
{
    ENU_MESSAGE_TYPE type_buff[MESSAGE_TYPR_BUF_NUM];   /* 读取事件缓冲区 */ 
    uint8_t out_point;                                  /* 读出指针 */ 
    uint8_t in_point;                                   /* 写入指针 */ 
}STR_MESSAGE_READ_CTR;


///////// 声明  全局变量 ///////////
STR_MESSAGE_READ_CTR      g_read_ctr;                                   /* 读取控制队列，同一时间只能读取一种类型*/ 

static  uint8_t g_store_in_to_out_buff[IN_FLASH_BUFF_SIZE];             /* 从内部flash读到外部flash的缓冲区 */ 
static  uint8_t g_read_send_buf[IN_FLASH_BUFF_SIZE];                    /* 读取 对外发送的缓冲区 */ 

STR_RECORD_INDEX    g_store_index[ENU_MESSAGE_TYPE_MAX] = {0};          /* 存储索引 */ 
STR_READ_INDEX      g_read_index[ENU_MESSAGE_TYPE_MAX] = {0};           /* 读取索引 */ 

STR_ADDR_INDEX      g_message_addr_index[ENU_MESSAGE_TYPE_MAX] = {0};   /* 存储地址与信息类型的关联 */      


/**
 * @brief change index in out flash
 * 
 * @param message 
 */
static void out_index_change(ENU_MESSAGE_TYPE message)
{
    /* 1, 外部的索引的页数加一  */
    g_store_index[message].out_page_num +=1;   

    if(g_store_index[message].out_page_num >= OUT_FLASH_PAGES_PRE_BLOCK)
    {
        /* 1.1, 外部的索引页数满一块，块数加一    */
        g_store_index[message].out_page_num =0;
        g_store_index[message].out_blocks_num +=1;

        if(g_store_index[message].out_blocks_num >= OUT_FLASH_BUFF_BLOCK_NUM)
        {
            /* 1.2, 外部的索引块数超过设置的最大块数，开始循环    */
            g_store_index[message].out_blocks_num = 0;
            g_store_index[message].out_is_cycle  = TRUE;

        }
    }
}


/**
 * @brief if in flash's buff is full,transfor data to out flash
 *      total record num = (cycle_flag * (OUT_FLASH_BUFF_BLOCK_NUM - 1))\
 *                          + pages * （OUT_FLASH_ONE_PAGE_SIZE/ONE_RECORD_SIZE） \
 *                          + record_num
 *      当循环标志置位，当前的存储总数是当前存储的这个块中的 已经存的内容 + 另外几块的全部内容。
 * @param message_type 
 */
static void in_flash_trans_to_out_flash(ENU_MESSAGE_TYPE message_type)
{
    /*  需要从内部整页读出的次数    */
    uint8_t  in_cycle_num = IN_FLASH_BUFF_SIZE/IN_FLASH_ONE_PAGE_SIZE;   
    /*   向外部flash中页写入的次数   */ 
    uint8_t  out_cycle_num = IN_FLASH_BUFF_SIZE/OUT_FLASH_ONE_PAGE_SIZE; 
    /*   已经从内部读出的长度   */    
    uint16_t in_readed_long = 0, out_write_long = 0;               
    /* 外部索引指向的 外部存储的写入偏移地址    */
    uint32_t out_addr_offset = 0;                                            

    /* 1，从内部flash中读出缓存的数据放入临时变量       */ 
    for(int addr_offset = 0; addr_offset < in_cycle_num; addr_offset++)
    {
        StrNvmOperaTable.pNVMReadByOffset(g_message_addr_index[message_type].in_addr_index,\
                                            (addr_offset*IN_FLASH_ONE_PAGE_SIZE),\
                                             &g_store_in_to_out_buff[in_readed_long], IN_FLASH_ONE_PAGE_SIZE);
       
        in_readed_long += IN_FLASH_ONE_PAGE_SIZE;
    }

    /* 2， 根据外部索引计算偏移地址                    */   
     out_addr_offset = g_store_index[message_type].out_blocks_num*OUT_FLASH_BLOCK_SIZE\
                        + g_store_index[message_type].out_page_num*OUT_FLASH_ONE_PAGE_SIZE;

    /* 3， 写入外部flash                             */ 
    for(int addr_offset = 0; addr_offset < out_cycle_num; addr_offset++)
    {
        /* 3.1, 根据外部存储索引的值，计算写入地址       */          
        StrNvmOperaTable.pNVMWriteByOffset(g_message_addr_index[message_type].out_addr_index, \
                                            (out_addr_offset + addr_offset*OUT_FLASH_ONE_PAGE_SIZE), \
                                            &g_store_in_to_out_buff[out_write_long],\
                                             OUT_FLASH_ONE_PAGE_SIZE);

        out_write_long += OUT_FLASH_ONE_PAGE_SIZE;
        out_index_change(message_type);
    }
}

/**
 * @brief Get the index CRC object
 * 
 * @return uint8_t CRC
 */
static uint8_t get_index_CRC(ENU_MESSAGE_TYPE message)
{
    uint8_t calcu_crc = 0xFF;  
    uint8_t ucPoly = 0x1D;
    
    uint8_t* p = (uint8_t*)&g_store_index[message];
      
    for (int i = 0; i < (sizeof(STR_RECORD_INDEX)-1); i++)
	{
		calcu_crc ^= p[i];

		for (int j = 0; j < 8; j++)
		{
			if (calcu_crc & 0x80)
			{
				calcu_crc = (calcu_crc << 1) ^ ucPoly;
			}
			else
			{
				calcu_crc <<= 1;
			}
		}
	}
	calcu_crc ^= (uint8_t)0xFF;
	return calcu_crc;
}

/**
 * @brief 存储索引更新
 * call this function when a new message has stored
 * 
 * @param message   type of store data 
 */
static void index_change(ENU_MESSAGE_TYPE message )
{  
    /* 1, check message value   */
    if(message >= ENU_MESSAGE_TYPE_MAX )
    {
        return;
    }
    /* 2, 存储索引进行修改          */
    g_store_index[message].in_record_num +=1;        
     
    if(g_store_index[message].in_record_num >= (IN_FLASH_BUFF_SIZE / ONE_RECORD_SIZE))
    {
        g_store_index[message].in_record_num = 0; 

        in_flash_trans_to_out_flash(message);//读到外部存储，
          
    }
           
    /* 3, 把索引更新到flash         */    
    g_store_index[message].Crc = get_index_CRC(message);
    StrNvmOperaTable.pNVMErase(DIDEX_RECORD_INDEX);
    StrNvmOperaTable.pNVMWrite(DIDEX_RECORD_INDEX, &g_store_index, sizeof(g_store_index));

}


//////////////////////单类型 读取控制/////////////////////////////////////////
/**
 * @brief 读取缓冲区 对外发送，
 *          根据读取设置的发送条数进行发送，发送条数归零后，清空发送状态
 *          发送状态是 status_seq 的高四位是 0XA，  低四位是 当前读取到的顺序
 *          每次读出的最大数量是内部缓冲区的大小，但是每次发送的条数是可以设置的，直到发送完毕，才会清空发送状态
 * 
 * @param message_type 
 */
static void read_buff_send(ENU_MESSAGE_TYPE message_type)
{
    uint16_t count = 0;
    uint16_t send_cycle_number = g_read_index[message_type].send_num;

    if(g_read_index[message_type].send_num != 0)
    {
         /*  发送条数不为零，进行发送  */
         printf("send \n");
        
        for(int i = 0; i< send_cycle_number;i++) // 发送缓冲区大小的数据
        {
              
            for(int j = 0; j<64; j++)
            {
                printf("%x ",g_read_send_buf[j + (count * ONE_RECORD_SIZE)]);

            }// 发送一条
            printf("\n");

            count++;
            g_read_index[message_type].send_num--;
        }    
    }
    else
    {
        /* 发送结束，复位发送状态，清空读取索引的发送缓冲区 */
         printf("send reset\n");
        RESET_SEND(g_read_index[message_type].read_status_seq);
        g_read_index[message_type].send_num = 0;
        c_bzero(g_read_send_buf , sizeof(g_read_send_buf));
    }
}



/**
 * @brief 修改 读取索引
 * 
 * @param message_type 
 */

static void read_index_change(ENU_MESSAGE_TYPE message_type)
{
    /* 1, 读取索引的外部的索引增加   */
    g_read_index[message_type].pages +=1;   
    
    if(g_read_index[message_type].pages >= OUT_FLASH_PAGES_PRE_BLOCK)
    {
        g_read_index[message_type].pages =0;
        g_read_index[message_type].blocks_num +=1;

        if(g_read_index[message_type].blocks_num >= OUT_FLASH_BUFF_BLOCK_NUM)
        {
            g_read_index[message_type].blocks_num = 0;
        }
    }
}

/**
 * @brief 从外部flash读出数据
 * 
 * @param message_type 
 */
static void read_out_block_page_message(ENU_MESSAGE_TYPE message_type)
{
    uint8_t current_read_block, store_blocks;
    uint8_t current_read_page, store_page;

    /* 读取索引 当前的外部读取位置   */ 
    current_read_block =  g_read_index[message_type].blocks_num;
    current_read_page = g_read_index[message_type].pages;

    /* 存储索引 当前最新保存的位置   */ 
    store_blocks = g_store_index[message_type].out_blocks_num;  
    store_page = g_store_index[message_type].out_page_num;

    /* 相关参数 初始化   */ 
    uint8_t  out_cycle_num = IN_FLASH_BUFF_SIZE/OUT_FLASH_ONE_PAGE_SIZE;     // 向外部flash中页读出的次数
    uint16_t  out_read_long = 0;                                             // 已经从外部读出的长度
    uint32_t  out_addr_offset = 0;  
    uint8_t * data_buff = g_read_send_buf;

     /* 1, 读取外部flash数据    */
     if( (current_read_block != store_blocks) || (current_read_page != store_page))  
    {
        /* 根据外部索引计算偏移地址 */  
        out_addr_offset = (current_read_block * OUT_FLASH_BLOCK_SIZE)\
                            + (current_read_page * OUT_FLASH_ONE_PAGE_SIZE);

        /* 读出外部flash    */ 
        for(int addr_offset = 0; addr_offset < out_cycle_num; addr_offset++)
        {
            // 根据外部存储索引的值，计算写入地址          
            StrNvmOperaTable.pNVMReadByOffset(g_message_addr_index[message_type].out_addr_index, \
                                                (out_addr_offset + addr_offset*OUT_FLASH_ONE_PAGE_SIZE), \
                                                &data_buff[out_read_long], OUT_FLASH_ONE_PAGE_SIZE);
            out_read_long += OUT_FLASH_ONE_PAGE_SIZE;
           read_index_change(message_type);
        }
        /* 设置发送条数 */ 
        g_read_index[message_type].send_num = IN_FLASH_BUFF_STORE_NUM;
        /* 设置发送状态 */
        SET_SEND(g_read_index[message_type].read_status_seq);
    }
    else
    {   
        /* 当 读取的位置与 存储的索引重合的时候，代表外部数据读完了，进行读内部数据  */
        printf("change to in data  \n");
        g_read_index[message_type].read_status_seq++;
    }
}


/**
 * @brief 读取内部缓冲区的数据
 * 
 * @param message_type 
 */
static void read_in_buff(ENU_MESSAGE_TYPE message_type)
{
    /*  1, 获得读取索引的发送缓冲区指针，存储索引的内部缓冲区存储的条数 */
    uint8_t * data_buff = g_read_send_buf;
    uint16_t record_in_num = g_store_index[message_type].in_record_num;  
    
    /*  2, 判断是否读取完成内部存储数据*/
    if(record_in_num != g_read_index[message_type].in_record_num)
    {
        StrNvmOperaTable.pNVMRead(g_message_addr_index[message_type].in_addr_index,\
                                                data_buff, (record_in_num*ONE_RECORD_SIZE));
        
        /*   设置 内部已经读取的条数   */ 
        g_read_index[message_type].in_record_num = record_in_num; 
        /*   设置发送条数   */ 
        g_read_index[message_type].send_num = record_in_num;
        /*  设置发送状态   */ 
        SET_SEND(g_read_index[message_type].read_status_seq);

    }
    else
    {
        /*  读取过程进入下一步   */ 
        printf("in data is read finish \n");
        g_read_index[message_type].read_status_seq++;
    }
}


static void finish_read_this_type(ENU_MESSAGE_TYPE message_type)
{
    g_read_index[message_type].start_read_flag = FALSE;
    g_read_index[message_type].read_status_seq = 0;
    g_read_index[message_type].in_record_num = 0;
    g_read_index[message_type].blocks_num = 0;
    g_read_index[message_type].pages = 0;
}

/**
 * @brief 设置要读取哪个类型的数据
 * 
 * @param message_type 
 */
static void select_message_to_read(ENU_MESSAGE_TYPE message_type)
{  
    uint16_t out_block_num = g_store_index[message_type].out_blocks_num;
    uint16_t out_page_num = g_store_index[message_type].out_page_num;

    /* 设置该类型记录允许读取 */ 
    g_read_index[message_type].start_read_flag = TRUE;

    /* 设置该类型数据外部存储的块数 */ 
    if((out_block_num != 0) && (out_page_num != 0))
    {
        if(g_store_index[message_type].out_is_cycle == FALSE)
        {
            g_read_index[message_type].blocks_num = 0;
        }
        else
        {
            g_read_index[message_type].blocks_num++;

            if(g_read_index[message_type].blocks_num >= OUT_FLASH_BUFF_BLOCK_NUM)
            {
                g_read_index[message_type].blocks_num = 0;
            }          
        }
    }
}


/**
 * @brief 在设置要读取的数据后，传入 读取类型，读出保存的数据
 * 
 * @param message_type 
 */
static void read_message(ENU_MESSAGE_TYPE message_type)
{      
    uint8_t status_seq = g_read_index[message_type].read_status_seq;

    if(IS_IN_SEND(status_seq))
    {        
        /* 1&2, if have data , send */
        read_buff_send(message_type);
    }
    else
    {
        
        switch (GET_SEQ(status_seq))
        {
            case ENU_OUT_BLOCK_PAGES_READ:
                printf("--block read \n");
                /* 1, read from out flash, if have data ,set send */
                read_out_block_page_message(message_type);
            break;
        
            case ENU_IN_BUFF_READ:
                printf(" --in  read \n");
                /* 2, read from in flash, if have data ,set send  */
                read_in_buff(message_type);
            break;
            
            case ENU_READ_FINFISH:
                /* 3, read is finished */
                g_read_index[message_type].start_read_flag = FALSE;
                finish_read_this_type(message_type);
            default:

            break;
        }               
    }   
}



////////////////读取控制事件管理///////////

/**
 * @brief 想要读取的记录类型缓冲区中移除已经读取过的类型
 * 
 */
static void read_ctrl_message_remove()
{
    /* 将刚刚读完的数据类型移除 */ 
    g_read_ctr.out_point = (g_read_ctr.out_point +1)&(MESSAGE_TYPR_BUF_NUM-1);

}

/**
 * @brief 获得想要 读取的记录类型的个数，最大4个
 * 
 * @return uint8_t 
 */
static  uint8_t read_ctr_message_buf_len()
{
    return (g_read_ctr.in_point - g_read_ctr.out_point)&(MESSAGE_TYPR_BUF_NUM-1);
}


/**
 * @brief 读取一种类型的全部记录
 * 
 * @param message_type 
 */
static void read_ctrl_get_one_type_message(ENU_MESSAGE_TYPE message_type)
{
    if( 0 == get_type_record_total_num(message_type))
    {
        printf("record is empty \n");
        read_ctrl_message_remove();
        return;
    }

     if(g_read_index[message_type].start_read_flag)
    {   
        read_message(message_type);
    }
    else
    {
        printf("read finish\n");
       read_ctrl_message_remove();
    }
}


///////////////////////  API  /////////////////////////////////////////////////////

/**
 * @brief 初始化 存储框架
 * init the store frim
 * 
 */
void store_index_init()
{
    uint16_t calcu_sum = 0;

    /* 1, 初始化NVM框架 */ 
    StrNvmOperaTable.pNvmConfig();

    /* 2, 关联 信息类型和信息存储的地址索引 */ 
    g_message_addr_index[ENU_FIRST_FIRE].in_addr_index =  DIDEX_IN_FIRST_FIRE_RECORD;
    g_message_addr_index[ENU_FIRST_FIRE].out_addr_index = DIDEX_OUT_FIRST_FIRE_RECORD;
    
    g_message_addr_index[ENU_ALARM].in_addr_index = DIDEX_IN_ALARM_RECORD;
    g_message_addr_index[ENU_ALARM].out_addr_index = DIDEX_OUT_ALARM_RECORD;
   
    g_message_addr_index[ENU_FAULT].in_addr_index = DIDEX_IN_FAULT_RECORD;
    g_message_addr_index[ENU_FAULT].out_addr_index = DIDEX_OUT_FAULT_RECORD;
   
    g_message_addr_index[ENU_OTHER].in_addr_index = DIDEX_IN_OTHER_RECORD;
    g_message_addr_index[ENU_OTHER].out_addr_index = DIDEX_OUT_OTHER_RECORD;

    /* 3, 初始化 存储索引 */
    StrNvmOperaTable.pNVMRead(DIDEX_RECORD_INDEX, &g_store_index, sizeof(g_store_index));
      
    for(int type = 0; type<ENU_MESSAGE_TYPE_MAX; type++)
    {      
        calcu_sum = 0;        
        calcu_sum = get_index_CRC(type);
        printf("g_store_index[type].Crc %d , calcu_sum %d \n",g_store_index[type].Crc, calcu_sum);
            
        if(g_store_index[type].Crc != calcu_sum)
        {      
            /* 清空 CRC校验不通过的记录索引，并擦除该类型的内部存储缓冲区 */
            printf("index is erro  clear all\n \n");  
            c_bzero(&g_store_index[type] , sizeof(STR_RECORD_INDEX));
            g_store_index[type].Crc = calcu_sum;

            DISABLE_IRQ();
            StrNvmOperaTable.pNVMErase(DIDEX_RECORD_INDEX);
            StrNvmOperaTable.pNVMWrite(DIDEX_RECORD_INDEX, &g_store_index, sizeof(g_store_index));  

            StrNvmOperaTable.pNVMErase(g_message_addr_index[type].in_addr_index);     
            ENABLE_IRQ();          
        }
    }
}


/**
 * @brief 将新传入的数据写入内部flash
 * 
 * @param infor 
 */
void store_new_message_to_in_flash(STR_MESSAGE_FORMAT *infor)
{
    if(infor == NULL)
    {
        printf("Infor  is  null \n");
        return ;
    }
   uint16_t event = infor->data_infor.event_type;
   ENU_MESSAGE_TYPE message_type;

    if(event == FIRST_ALALRM_CODE)
    {
        message_type = ENU_FIRST_FIRE;
    }
    else if(event == FIRE_ALARM_CODE)
    {
        message_type = ENU_ALARM;
    }
     else if(((event >= FAULT_CODE_LOW) && (event <= FAULT_CODE_HIGHT)) \
            || ((event >= POWER_FAULT_CODE_LOW) &&(event <= POWER_FAULT_CODE_HIGH)))
    {
        message_type = ENU_FAULT;
    }
    else
    {
        message_type = ENU_OTHER;
    }

     if(g_store_index[message_type].in_record_num == 0)
    {
        DISABLE_IRQ();
        StrNvmOperaTable.pNVMErase(g_message_addr_index[message_type].in_addr_index);
        ENABLE_IRQ();
    }
   
    DISABLE_IRQ();   
    StrNvmOperaTable.pNVMWriteByOffset(g_message_addr_index[message_type].in_addr_index,\
                                    ONE_RECORD_SIZE * g_store_index[message_type].in_record_num,\
                                    infor,\
                                    sizeof(STR_MESSAGE_FORMAT));
    ENABLE_IRQ();
    index_change(message_type);
}


/**
 * @brief Get one type record total num object
 * 
 * @param message_type 
 * @return uint32_t 
 */
uint32_t get_type_record_total_num(ENU_MESSAGE_TYPE message_type)
{
    uint8_t  cycle_flag = g_store_index[message_type].out_is_cycle;
    uint16_t in_buff_record = g_store_index[message_type].in_record_num;
    uint16_t block_num = g_store_index[message_type].out_blocks_num;  
    uint16_t out_pages_num  = g_store_index[message_type].out_page_num;
    uint32_t blocks_record_total = 0;
    uint32_t out_record_num_per_page = OUT_FLASH_ONE_PAGE_SIZE/ONE_RECORD_SIZE;
    
   if(cycle_flag == TRUE)
   {
    /*
        (  当前块记录的条数（页数*每页的条数） )
        + (
                已经开始循环则已经使用完的块数（分配N+1块，除了当前存储的块，其他块都存满了）
             * 一块存储多少条
           )
    */
        blocks_record_total = (out_pages_num*out_record_num_per_page)\
                                    + (
                                        cycle_flag*(OUT_FLASH_BUFF_BLOCK_NUM-1)\
                                        *(out_record_num_per_page*OUT_FLASH_PAGES_PRE_BLOCK) 
                                      );
   }
   else
   {
    /*
        (  当前块记录的条数（页数*每页的条数） )
        + (
                没有循环则已经完全使用完的块数（当前第几块）
             * 一块存储多少条
           )
    */
        blocks_record_total = (out_pages_num*out_record_num_per_page)\
                                    + (
                                        (block_num)\
                                        *(out_record_num_per_page*OUT_FLASH_PAGES_PRE_BLOCK) 
                                      );
   }
   
    // printf("in_record_num   %x  \n",g_store_index[message_type].in_record_num );
    // printf("out_page_num    %x\n",g_store_index[message_type].out_page_num );
    // printf("out_blocks_num  %x\n",g_store_index[message_type].out_blocks_num );
    // printf("out_is_cycle    %x\n",g_store_index[message_type].out_is_cycle );  
    // printf("-------------------------------------\n");


  return (blocks_record_total+in_buff_record);
}




/**
 * @brief Get all record total num object 
 * 
 */
uint32_t get_all_record_number()
{
     uint32_t all_number = 0;
    
    for(int type_index = 0; type_index < ENU_MESSAGE_TYPE_MAX; type_index++)
    {
        all_number = get_type_record_total_num((ENU_MESSAGE_TYPE)type_index);
    }
    return all_number;
}

/**
 * @brief 对 读取索引进行初始化，设置开始读的起始块位置
 * 
 * @param message_type 
 */

void read_index_init()
{ 
    c_bzero(g_read_index , sizeof(g_read_index)); // 清空读取索引
}

/**
 * @brief 设置想读出的数据
 * 
 * @param message_type 
 */
void read_ctrl_message_add(ENU_MESSAGE_TYPE message_type)
{
    /* 1, 填充读取类型到 事件缓冲区 */
    uint8_t in_point = g_read_ctr.in_point;
    printf("dessage type %d \n",message_type);
    g_read_ctr.type_buff[in_point] = (message_type);
    g_read_ctr.in_point = (g_read_ctr.in_point +1)&(MESSAGE_TYPR_BUF_NUM-1);
    printf("g_read_ctr.in_point %d \n",g_read_ctr.in_point);
    
    /* 2, 设置读取的信息类型做读取准备 */ 
    select_message_to_read(message_type);
}

/**
 * @brief 读取调度函数，使用 select_message_to_read 函数选择读取的类型
 *          类型按照 
 * 
 */
void read_ctrl_schdule()
{
    uint8_t current_point  = g_read_ctr.out_point;
    ENU_MESSAGE_TYPE current_message_type = g_read_ctr.type_buff[current_point];
  
    if(read_ctr_message_buf_len())
    {
        read_ctrl_get_one_type_message(current_message_type);
    }
}


/**
 * @brief 清除 指定类型的全部记录
 * 
 * @param message_type 指定类型
 */
void clear_record(ENU_MESSAGE_TYPE message_type)
{
    c_bzero(&g_store_index[message_type] , sizeof(STR_RECORD_INDEX));
    StrNvmOperaTable.pNVMErase(DIDEX_RECORD_INDEX);
    StrNvmOperaTable.pNVMWrite(DIDEX_RECORD_INDEX, &g_store_index, sizeof(g_store_index));           
    StrNvmOperaTable.pNVMRead(DIDEX_RECORD_INDEX, &g_store_index, sizeof(g_store_index));
}








